dojo.provide("lotex.report.Sheet");
dojo.require("dojo.lang.declare");
dojo.require("lotex.report.Cell");
dojo.require("lotex.report.Row");

dojo.declare("lotex.report.Sheet", null, {
    initializer: function(table, idx) {
        this.table = table;
        this.idx = idx;

        this.rows = [];

        this.groupOffset = 0;

        this.parse();
        tic();
        lotex.report.Parser.p2(this);
        toc("parse sheet");
    },

    addRow: function(row) {
        row.parent = this;
        this.rows.push(row);
    },

    appendCol: function(num) {
        if(!num) var num = 1;
        var len = this.getRowLen();
        for(var i=0;i<len;i++) {
            this.rows[i].addCell(new lotex.report.Cell());
        }
    },

    appendRow: function(num) {
        if(!num) var num = 1;
        var len = this.getColLen();
        var row = new lotex.report.Row();
        for(var i=0;i<len;i++) {
            row.addCell(new lotex.report.Cell());
        }
        for(var i=0;i<num;i++) {
            this.addRow(row.clone());
        }
    },

    copyProperty: function() {
    },

    expandRow: function(row,expand) {
        this.rows.splice.apply(this.rows,
            dojo.lang.unnest(row,1,expand));
        // TODO maybe need update header[] and data[]...cache
        var len = expand.length;
        //this.updateOffset(this.__group, row, len-1);
        var __expand = [];
        for(var i=0;i<len;i++) {
            __expand.push(row+i);
        }
        this.__expand=__expand;
    },

    findVisualCell: function(row, offset) {
        if(!offset) offset = 1;
        //var ooo =this.rows;var fff=iii;
        var x = this.getColLen();
        for(var col=0; col<x; col++) {
            var cell = this.rows[row].cells[col];
            if(cell.beMerge) continue;
            offset--;
            if(offset==0) return col;
        }
        return null;
    },

    getCell: function(col,row,scope) {
        // TODO scope default process/remove
        var y = this.getRowLen();
        var x = this.getColLen();
        //var cell = this.rows[row].cells[col];
        //cell.getConfig();
        var cell = lotex.report.Functions.context.cell;
        var cfg = cell.getConfig();
        if(row==null) {
            if (scope==lotex.report.Constants.SCOPE_GROUP) {
                return this.getGroupCell(cfg.group, col);
            }
//b();
            var ret = [];
            for(var i=0;i<y;i++) {
                //if hasExpstr()
                if(this.rows[i].cells[col].isData)
                    ret.push(this.getCell(col,i));
            }
            return ret;
        }
        if (col<0 || col>=x
            || row<0 || row>= y)
            return null;
        var vv = this.rows[row].cells[col].value;
        //d(vv);
        return vv;
    },

    getColLen: function() {
        return this.rows[0].cells.length;
    },

    getDataset: function() {
        var cfg = this.getConfig();
        var dsn = cfg.datasource;
        return this.parent.getDataset(dsn);
    },

    getGroupCell: function(gname, col) {
        // col to db field idx
        var ds = this.getDataset();
        var group = ds.group[gname][this.groupOffset];
        var len = group.length;

        var ret = [];
        for(var i=0;i<len;i++) {
            ret.push(ds.table.data[group[i]][col])
        }
        this.groupOffset++;

        return ret;
    },

    getRowLen: function() {
        return this.rows.length;
    },

    insertBlankRow: function(idx) {
        var row = new lotex.report.Row();
        var x = this.getColLen();
        for(var col=0; col<x; col++) {
            row.addCell(new lotex.report.Cell());
        }
        row.parent = this;
        this.rows.splice(idx,0,row);
    },

    insertInExpand: function(idx,row) {
        var __expand = this.__expand;
        var inpos = (idx > __expand.length) ?
            __expand[__expand.length-1] +1 : __expand[idx-1];
        this.rows.splice(inpos,0,row);
        this.updateOffset(this.__expand,inpos,1)
        this.__expand.splice(inpos-1,0,inpos);
    },

    insertRow: function(idx,row) {
        this.rows.splice(idx,0,row);
        this.updateOffset(this.__expand,idx,1)
    },

    isDataSheet: function() {
        return this.__data.length==0 ? false : true;
    },

    parse: function() {
        this.initClassFromDOM(this.table);
        var maxRowIdx = this.table.rows.length;

        var col = 0;
        for (var i=0; i<this.table.rows[0].cells.length; i++) {
            var cell = this.table.rows[0].cells[i];
            col += (cell.colSpan) ? cell.colSpan : 1;
        }
        var maxColIdx = col;

        //TPL table to Object
        this.copyProperty(this.table);

        //Init row..structure
        for(var i=0; i<maxRowIdx; i++) {
            this.addRow(new lotex.report.Row());
            for(var j=0; j<maxColIdx; j++) {
                this.rows[i].addCell(new lotex.report.Cell());
            }
        }

        for(var i=0; i<maxRowIdx; i++) {
            this.rows[i].copyProperty(this.table.rows[i]);
            for(var j=0; j<this.table.rows[i].cells.length; j++) {
                var tdel = this.table.rows[i].cells[j];
                var cellCol = this.findVisualCell(i, j+1);
                var cell = this.rows[i].cells[cellCol];
                cell.copyProperty(tdel);

                var rs = cell.rowSpan;
                var cs = cell.colSpan;
                for(var mr=0; mr<rs; mr++) {
                    for(var mc=0; mc<cs; mc++) {
                        if (mr==0 && mc==0) continue;
                        this.rows[i+mr].cells[cellCol+mc].beMerge = true;
                    }
                }
            }
        }
    },

    plus: function(sheet2) {
        var r1 = this.getRowLen();
        var r2 = sheet2.getRowLen();
        if(r1!=r2) {
            var needAddRow = r1 > r2 ? sheet2 : this;
            needAddRow.appendRow(Math.abs(r1-r2));
        }
        var rowLen = r1>r2 ? r1: r2;
        var colLen = sheet2.getColLen();
        for(var i=0;i<rowLen;i++) {
            for(var j=0;j<colLen;j++) {
                this.rows[i].addCell(sheet2.rows[i].cells[j]);
            }
        }
        return this;
    },

    plusV: function(sheet2) {
        var r1 = this.getColLen();
        var r2 = sheet2.getColLen();
        if(r1!=r2) {
            var needAddRow = r1 > r2 ? sheet2 : this;
            needAddRow.appendCol(Math.abs(r1-r2));
        }
        var len = sheet2.getRowLen();
        for(var i=0;i<len;i++) {
            this.addRow(sheet2.rows[i]);
        }
        return this;
    },

    readConfig: function() {
        var cfg = this.parent.data.config;
        var _C = lotex.report.Constants;
        cfg.datasource = this.getConfigItem(
            "datasource", _C.DATASOURCE_DEFAULT);

        cfg.field = this.parent.getDataset(cfg.datasource).table.field;

        cfg.datasource = this.getConfigItem(
            "datasource", _C.DATASOURCE_DEFAULT);
        return cfg;
    },

    torsional: function() {
        var r = this.getRowLen();
        var c = this.getColLen();
        var rows = [];
        for(var i=0;i<c;i++) {
            rows.push(new lotex.report.Row());
        }
        for(var i=0;i<c;i++) {
            for(var j=0;j<r;j++) {
                var cell = this.rows[j].cells[i];
                var _rowSpan = cell.rowSpan;
                cell.rowSpan = cell.colSpan;
                cell.colSpan = _rowSpan;
                rows[i].addCell(cell);
            }
        }
        this.rows = rows;
        return this;
    },

    toStr: function() {
        var s = [];
        s.push('<table');
        s.push(this.getClassStr());
        s.push('>\n');
        for (var i=0; i<this.rows.length; i++) {
            s.push(this.rows[i].toStr()+'\n');
        }
        s.push('</table>');
        return s.join('');
    },

    updateOffset: function(a, row, l) {
        if(!a) return;
        var len=a.length;
        for (var i=0;i<len;i++) {
            if(a[i]>=row) a[i] += l;
        }
    }
});

dojo.lang.extend(lotex.report.Sheet, lotex.report.AbstractReport);